package com.putao.web.controller;

import com.alibaba.fastjson.JSON;
import com.putao.base.JwtUser;
import com.putao.constants.OAuthConstant;
import com.putao.enums.VerifyCodeEnum;
import com.putao.feign.WebsocketFeign;
import com.putao.redis.service.IRedisService;
import com.putao.result.JsonResult;
import com.putao.result.WebsocketResult;
import com.putao.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.Map;

@RestController
@Slf4j
public class AuthController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private TokenEndpoint tokenEndpoint;
    @Autowired
    private CheckTokenEndpoint checkTokenEndpoint;
    @Autowired
    private TokenStore tokenStore;
    @Autowired
    private WebsocketFeign websocketFeign;
    @Autowired
    private IRedisService redisService;

    @GetMapping("/oauth/token")
    public JsonResult getToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        return this.postToken(principal, parameters);
    }

    @PostMapping("/oauth/token")
    public JsonResult postToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        if (StringUtils.isNotBlank(parameters.get("key"))) {
            parameters.put("client_id", "qrcode_client_id");
            parameters.put("client_secret", "123");
            return tokenByQrcode(principal, parameters);
        }
        OAuth2AccessToken auth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
        return JsonResult.resultSuccess(auth2AccessToken, null);
    }

    public JsonResult tokenByQrcode(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        OAuth2AccessToken auth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
        /**
         * 流程
         * 1、前端发送请求到后台，后台生成一个uuid，并将uuid生成二维码，然后返回给pc，发送延迟消息给mq，1分钟后检查qrcode的状态是否为扫了，反之过期
         * 2、pc上显示二维码，然后用户使用记账app扫码，跳转到授权页面，并识别二维码是 key，根据key和自身的 Authorization 取出用户id发送请求到oauth/token，（目前想到的方式）
         * 3、服务器收到请求后处理请求，正常走完授权流程后（已经处理判断二维码是否已经过期），然后判断是否为二维码登录，是的话取出key然后发送消息给pc端（包含token）
         * 4、pc端接收到token后提示用户扫码登录成功，然后跳转到系统首页
         */
        // 判断类型，如果是qrcode的话再根据key发送消息给前端，登录成功
        String key = parameters.get("key");
        // 根据uuid拼接成key然后将value的时间设置为0，或者删除，这样就能保证mq处理消息时不会发送消息给pc
        redisService.deleteKey(VerifyCodeEnum.QR_CODE_TIME_OUT.join(key));
        websocketFeign.sendMessage(WebsocketResult.loginSuccess(auth2AccessToken, key));
        return JsonResult.resultSuccess(null, null);
    }

    @GetMapping("/oauth/check_token")
    public JsonResult postToken(@RequestParam String token) throws HttpRequestMethodNotSupportedException {
        Map<String, ?> stringMap = checkTokenEndpoint.checkToken(token);
        return JsonResult.resultSuccess(stringMap, null);
    }

    @GetMapping("/oauth/createToken")
    public JsonResult createToken(@RequestParam String clientId, Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        //ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
        //TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
        //OAuth2AccessToken accessToken = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
        OAuth2AccessToken accessToken = null;
        return JsonResult.resultSuccess(accessToken, null);
    }

    @PostMapping("/oauth/logout")
    public JsonResult logout(HttpServletRequest request){
        String authorization = request.getHeader("Authorization").replace("bearer ", "");
        Jwt jwt= JwtHelper.decode(authorization);
        String claims=jwt.getClaims();
        JwtUser jwtUser = JSON.parseObject(claims, JwtUser.class);
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(authorization);
        log.error("oAuth2AccessToken.getExpiration().getTime() = " + oAuth2AccessToken.getExpiresIn());
//        LoginVal loginVal = OauthUtils.getCurrentUser();
        // 这个jti放入redis中，并且过期时间设置为token的过期时间
        redisService.setAndTime(OAuthConstant.JTI_KEY_PREFIX + jwtUser.getJti(),"", (long) oAuth2AccessToken.getExpiresIn());
        return JsonResult.logoutSuccess(null, null);
    }

    public static void main(String[] args) {
        Jwt jwt= JwtHelper.decode("yJhGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.yJhdWQiOlsicmVzMSJdLCJwG9uZSI6IjE4ODEzNDQyNDM1IiwidXNlcl9uYW1lIjoiYWRtW4iLCJzY29wZSI6WyJhGwiXSwiWQiOiJmYzczZjIxMzg4N2Q4ZTQ4NTZiOWUyNzU2NjU2NTk5YSIsImF2YXRhciI6Imh0dHBzOi8vdGhpcmR3C5xG9ny5ji9tW9wZW4vdmlfMzIvU1BGODhDTWVWVHBz01VWjhtSlp2Tk9jSFg1NGZyjZYVREG8wYjRxSmpXldvDNSTW0yRlJZOW05FFxOFBBWUp1dG9O09BWs2VWN5mFGdXcvMTMyIiwiZXhwIjoxNjU4ODgwOTQwLCJhdXRo3JpdGllcyI6WyJST0xFX2FkWluIl0sImp0SI6IjAyMWIzNDRlLWYxNjMtNDQxNC1iMmI2LWI2Y2YwMWY4ZThkNyIsImVtYWlsIjoiMjYyODI3OTE5NEBxcS5j20iLCJjGllnRfWQiOiJtdWd1IiwidXNlcm5hWUiOiJhZG1piJ9.v9Y05XZsOoOYqZTxjRNXuuAhDzophfFIpwl0PPq38");
        String claims=jwt.getClaims();
        String encoded=jwt.getEncoded();
        System.out.println("claims 原始信息："+claims);       //获取原始信息json字符串
        JwtUser jwtUser = JSON.parseObject(claims, JwtUser.class);
        System.out.println("access token编码信息："+encoded); //获取编码后的字符串
    }
}
